home *** CD-ROM | disk | FTP | other *** search
/ CD ROM Paradise Collection 4 / CD ROM Paradise Collection 4 1995 Nov.iso / program / swagd_f.zip / DATATYPE.SWG / 0020_Huffman BTree.pas < prev    next >
Pascal/Delphi Source File  |  1995-03-03  |  6KB  |  195 lines

  1. {
  2. From: nrivers@silver.ucs.indiana.edu (n paul rivers)
  3.  
  4.    I did manage to find part of the code that was once used to write
  5. a preliminary version of a Huffman compression program.  Oddly, some of
  6. the procedures were missing, and worse, there were no comments.  I
  7. apologize for all this, but hopefully it will be some use in spite of
  8. the inadequacies.  Also, your post makes mention of wanting the "optimum"
  9. way to do this -- well, this isn't it!  But it will work, and perhaps it
  10. will give you some ideas.
  11. }
  12.  
  13. Type
  14.   TNodePtr = ^TNode;
  15.   TNode = Record
  16.     Count : Longint;
  17.     Parent, Left, Right : TNodePtr;
  18.     end;
  19.   TNodePtrArray = Array[0..255] of TNodePtr;
  20.   TFreqArray = Array[0..255] of Longint;
  21.   TFileName = String[12];
  22.   TBitTable = Array[0..255] of Byte;
  23.  
  24. Var
  25.   Source, Dest : TFileName;
  26.   LeafNodes : TNodePtrArray;
  27.   Freq : TFreqArray;
  28.   BitTable : TBitTable;
  29.   TotalBytes : Longint;
  30.   P : Pointer;
  31.   C : Char;
  32.  
  33. Procedure GetFileNames(var Source, Dest : TFileName);
  34.   Begin
  35.     If ParamCount<>2 then begin
  36.        writeln('Specify the file to compress & its destination name.');
  37.        writeln; halt; end;
  38.     Source := ParamStr(1);
  39.     Dest := ParamStr(2);
  40.   End;
  41.  
  42. Procedure InitializeArrays(var Leaf : TNodePtrArray; 
  43.           var Freq : TFreqArray; var BitTable : TBitTable);
  44.   Var
  45.     B : Byte;
  46.   Begin
  47.     For B := 0 to 255 do begin
  48.       Leaf[B] := nil;
  49.       Freq[B] := 0;
  50.       BitTable[B] := '';
  51.     End;
  52.   End;
  53.  
  54. Procedure GetByteInfo(Source : TFileName; var Freq : TFreqArray; 
  55.                       var TotalBytes : Longint);
  56.   Var
  57.     S : File of Byte;
  58.     inputByte : Byte;
  59.   Begin
  60.     Assign(S, Source);
  61.     Reset(S);
  62.     TotalBytes := 0;
  63.     While not(eof(s)) do begin
  64.       read(s,inputByte);
  65.       Inc(Freq[inputByte]);
  66.       Inc(TotalBytes);
  67.     end;
  68.     Close(S);
  69.   End;
  70.  
  71. Procedure LoadNodeArray(var LeafNodes : TNodePtrArray; 
  72.                         var Freq : TFreqArray);
  73.   Var
  74.     B : Byte;
  75.     Node : TNodePtr;
  76.   Begin
  77.     Node := Nil;
  78.     For B := 0 to 255 do if Freq[B]>0 then begin
  79.       New(Node);
  80.       Node^.Parent := nil;
  81.       Node^.Left := nil;
  82.       Node^.Right := nil;
  83.       Node^.Count := Freq[B];
  84.       LeafNodes[B] := Node;
  85.       Node := Nil;
  86.     End;
  87.   End;
  88.  
  89. Procedure GetMinInFreeArray(var min1, min2 : byte; var CFA : TNodePtrArray);
  90.   Var b : byte;
  91.       minCount1, minCount2 : Longint;
  92.   Begin
  93.     minCount1 := 1000000000; minCount2 := minCount1;
  94.     min1 := 0; min2 := 0;
  95.     for b := 0 to 255 do if CFA[b]<>nil then begin
  96.       if minCount1>CFA[b]^.Count then begin
  97.          min2 := min1; min1 := b;
  98.          minCount2 := minCount1; minCount1 := CFA[b]^.Count;
  99.          end
  100.       else if ((minCount2>=CFA[b]^.Count) and (b<>min1)) then begin
  101.          minCount2 := CFA[b]^.Count; min2 := b;
  102.          end;
  103.     end;
  104.   End;
  105.  
  106.  
  107. Procedure BuildTree(var LeafNodes : TNodePtrArray);
  108.   Var
  109.      CFA, NFA : TNodePtrArray;  Node : TNodePtr;
  110.      {CFA = current free array,  NFA = next free array
  111.       once two nodes in the current free array have been combined to
  112.       form one node at one level 'up' the tree, then this new node must
  113.       be placed in the NFA for the upcoming round of combining nodes}
  114.      FreeThisLvl, NoCombs : Word;
  115.      {FreeThisLvl = continue combining nodes at each level until after one
  116.       round of combining, there is only one node left.  "there can be only
  117.       one!"  NoCombs = number of combinations to be made at the given level"}
  118.      Cnt, min1, min2 : Byte;
  119.   Begin
  120.      FreeThisLvl := 0; Node := nil;
  121.      for cnt := 0 to 255 do begin
  122.          NFA[cnt] := nil;
  123.          CFA[cnt] := LeafNodes[cnt];
  124.          if CFA[cnt]<>nil then Inc(FreeThisLvl);
  125.      end;
  126.  
  127.      While FreeThisLvl>1 do begin
  128.        NoCombs := (FreeThisLvl div 2);
  129.        For cnt := 1 to NoCombs do begin
  130.            GetMinInFreeArray(min1,min2,CFA);
  131.            New(Node);
  132.            Node^.Parent := nil;
  133.            Node^.Right := CFA[min1]; Node^.Left := CFA[min2];
  134.            Node^.Count := CFA[min1]^.Count + CFA[min2]^.Count;
  135.            Node^.Left^.Parent := Node;
  136.            Node^.Right^.Parent := Node;
  137.            NFA[cnt] := Node; Node := Nil;
  138.            CFA[min1] := nil; CFA[min2] := nil;
  139.        end;
  140.  
  141.        For cnt := 0 to 255 do if CFA[cnt]<>nil then NFA[0] := CFA[cnt];
  142.  
  143.        For cnt := 0 to 255 do begin
  144.          CFA[cnt] := NFA[cnt];
  145.          NFA[cnt] := nil;
  146.        end;
  147.  
  148.        FreeThisLvl := 0;
  149.        For cnt := 0 to 255 do if CFA[cnt]<>nil then Inc(FreeThisLvl);
  150.  
  151.      end;
  152.   End;
  153.  
  154. Procedure BuildBitTable(var LeafNodes : TNodePtrArray; 
  155.                         var BitTable : TBitTable)
  156.   Begin
  157.     {
  158.     To build the bit table for a given value, set, e.g. ptr1 and ptr2, to
  159.     point to the given leafnode.  then set ptr1 to point at the parent.
  160.     then if ptr1^.left = ptr2 then the first bit for the given node is 0,
  161.     else it is 1.  continue this process until you reach the top of the 
  162.     tree.
  163.     }
  164.   End;
  165.  
  166. Procedure CompressFile(Source, Dest : TFileName; var BitTable : TBitTable; 
  167.                        TotalBytes : Longint);
  168.   Begin
  169.     {
  170.     remember to write the necessary tree information for decompression in
  171.     the compressed file.  also, since the last byte of the file might 
  172.     contain bits not relevant to decoding, i've decided to just keep track
  173.     of the total # of bytes in the original file.  so don't forget to
  174.     write this number to the file as well.
  175.     }
  176.   End;
  177.  
  178. BEGIN
  179.  
  180.   GetFileNames(Source,Dest);
  181.   InitializeArrays(LeafNodes,Freq,BitTable);
  182.   writeln('Gathering info...'); writeln;
  183.   GetByteInfo(Source,Freq,TotalBytes);
  184.   Mark(P);
  185.   LoadNodeArray(LeafNodes,Freq);
  186.   BuildTree(LeafNodes);
  187.   BuildBitTable(LeafNodes,BitTable);
  188.   Release(P);
  189.   writeln('Compressing file...'); writeln;
  190.   CompressFile(Source,Dest,BitTable,TotalBytes);
  191.   writeln; writeln;
  192.  
  193. END.
  194.  
  195.